////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011-2012 Kentaro Sekimoto  All rights reserved.
////////////////////////////////////////////////////////////////////////////

#include <tinyhal.h>
#include "..\FM3.h"
#include "FM3_Analog_functions.h"

#ifdef MB9BF618T
const UINT8 FM3_AD_Driver::c_Pins[FM3_AD_Driver::c_Channels] =
{
        P10, P11, P12, P13,
        P14, P15, P16, P17,
        P18, P19, P1A, P1B,
        P1C, P1D, P1E, P1F,
        PB0, PB1, PB2, PB3,
        PB4, PB5, PB6, PB7,
        PB8, PB9, PBA, PBB,
        PBC, PBD, PBE, PBF
};
#else
#ifdef MB9BF506N
const UINT8 FM3_AD_Driver::c_Pins[FM3_AD_Driver::c_Channels] =
{
        P10, P11, P12, P13,
        P14, P15, P16, P17,
        P18, P19, P1A, P1B,
        P1C, P1D, P1E, P1F
};
#else
#error "CPU type not defined. Please define MB9BF506N or MB9BF618T!"
#endif
#endif

FM3_AD_Driver g_FM3_AD_Driver;

BOOL AD_Initialize(ANALOG_CHANNEL channel, INT32 precisionInBits)
{
    UINT32 ch = (UINT32)channel;
    if (ch >= g_FM3_AD_Driver.c_Channels)
        return FALSE;
    if (precisionInBits == 12) {
#ifdef MB9BF618T
        if (ch < 16)
            FM3_GPIO->PFR1 |= (1 << ch);
        else
            FM3_GPIO->PFRB |= (1 << (ch-16));
#endif
#ifdef  MB9BF506N
        FM3_GPIO->PFR1 |= (1 << ch);
#endif
        FM3_GPIO->ADE |= (1 << ch);
        FM3_ADC0->ADCT = 3;
        FM3_ADC0->ADCEN = ADCEN_ENBL;
        while((FM3_ADC0->ADCEN & ADCEN_READY) != ADCEN_READY) ;
#ifdef MB9BF618T
        if (ch < 8) {
            FM3_ADC0->SCIS0 |= (1 << ch);
        } else if (ch < 16) {
            FM3_ADC0->SCIS1 |= (1 << (ch-8));
        } else if (ch < 24) {
            FM3_ADC0->SCIS2 |= (1 << (ch-16));
        } else {
            FM3_ADC0->SCIS3 |= (1 << (ch-24));
        }
#endif
#ifdef MB9BF506N
        if (ch < 8) {
            FM3_ADC0->SCIS0 |= (1 << ch);
        } else {
            FM3_ADC0->SCIS1 |= (1 << (ch-8));
        }
#endif
        FM3_ADC0->ADST0 = 0xA9;     // STX:6=x64, ST:9=x(9+1),  -> 64 x (9 + 1) + 1 = 641
        FM3_ADC0->ADST1 = 0xA9;     // PCLK 72MHz=13.9ns -> 13.9ns x 641 = 8910ns
        FM3_ADC0->CMPCR = ch;
        FM3_ADC0->ADSR = ADSR_FDAS; // ADSTP(R/W):0, FDAS(R/W):1(LSB), , , , PCNS(R):0, PCS(R):0, SCS(R):0
        FM3_ADC0->ADCR = 0;         // SCIF:0, PCIF:0, CMPIF:0, , SCIE:0 , PCIE:0 , CMPIE:0, OVRIE:0
        FM3_ADC0->SCCR |= SCCR_SFCLR;
        FM3_ADC0->SCCR &= ~SCCR_RPT;
        return TRUE;
    } else
        return FALSE;
}

void AD_Uninitialize(ANALOG_CHANNEL channel)
{
    UINT32 ch = (UINT32)channel;
#ifdef MB9BF618T
    if (ch < 16)
        FM3_GPIO->PFR1 &= ~(1 << ch);
    else
        FM3_GPIO->PFRB &= ~(1 << (ch-16));
#endif
#ifdef  MB9BF506N
    FM3_GPIO->PFR1 &= ~(1 << ch);
#endif
    FM3_GPIO->ADE &= ~(1 << ch);
}

INT32 AD_Read(ANALOG_CHANNEL channel)
{
    volatile UINT32 value32;
    FM3_ADC0->SCCR |= SCCR_SSTR;    // A/D start
    do {
        value32 = FM3_ADC0->SCFD;
    } while (((value32 & SCFDL_INVL) != 0) || ((UINT32)channel != (value32 & 0x1F)));
    FM3_ADC0->SCCR = (FM3_ADC0->SCCR | SCCR_SFCLR) & ~(SCCR_RPT | SCCR_SOVR);    // A/D stop
    return (value32 >> 16);
}

UINT32 AD_ADChannels()
{
    return FM3_AD_Driver::c_Channels;
}

GPIO_PIN AD_GetPinForChannel(ANALOG_CHANNEL channel)
{
    if ((UINT32)channel >= g_FM3_AD_Driver.c_Channels)
        return GPIO_PIN_NONE;
    return (GPIO_PIN)g_FM3_AD_Driver.c_Pins[(UINT32)channel];
}

BOOL AD_GetAvailablePrecisionsForChannel(ANALOG_CHANNEL channel, INT32* precisions, UINT32& size)
{
    size = 0;
    if (precisions == NULL || (UINT32)channel >= g_FM3_AD_Driver.c_Channels)
        return FALSE;
    precisions[0] = 12;
    size = 1;
    return TRUE;
}
